<template>
  <div class="dashboard">
    <!-- 顶部标题 -->
    <div class="dashboard__header">
      <div class="dashboard__title">仪表板</div>
      <div class="dashboard__subtitle">系统概览和关键指标（模拟数据）</div>
    </div>

    <!-- 统计卡片 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24" :sm="12" :xl="6">
        <el-card shadow="hover" class="stat-card stat-card--primary">
          <div class="stat-card__header">总用户数</div>
          <el-statistic :value="stats.totalUsers" />
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="12" :xl="6">
        <el-card shadow="hover" class="stat-card stat-card--success">
          <div class="stat-card__header">今日订单</div>
          <el-statistic :value="stats.todayOrders" />
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="12" :xl="6">
        <el-card shadow="hover" class="stat-card stat-card--info">
          <div class="stat-card__header">产品数量</div>
          <el-statistic :value="stats.totalProducts" />
        </el-card>
      </el-col>
      <el-col :xs="24" :sm="12" :xl="6">
        <el-card shadow="hover" class="stat-card stat-card--warning">
          <div class="stat-card__header">月收入</div>
          <el-statistic :value="stats.monthlyRevenue" />
        </el-card>
      </el-col>
    </el-row>

    <!-- 控件区 -->
    <el-card class="dashboard__controls" shadow="never">
      <div class="controls__row">
        <el-date-picker
          v-model="filters.dateRange"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          :unlink-panels="true"
          size="small"
        />
        <el-select v-model="filters.period" size="small" style="width: 160px">
          <el-option label="近7天" value="7" />
          <el-option label="近30天" value="30" />
        </el-select>
        <el-button type="primary" size="small" @click="applyFilters">应用筛选（模拟刷新）</el-button>
      </div>
    </el-card>

    <!-- 第一行：折线 + 柱状 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div>
                <span class="card-header__title">销售趋势</span>
                <span class="card-header__hint">模拟数据每3秒刷新</span>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="downloadPNG('sales')">PNG</el-button>
                <el-button size="small" type="text" @click="downloadCSV('sales')">CSV</el-button>
                <el-button size="small" type="text" @click="downloadExcel('sales')">Excel</el-button>
              </div>
            </div>
          </template>
          <div class="chart-area">
            <div ref="salesChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>

      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div>
                <span class="card-header__title">每周订单量</span>
                <span class="card-header__hint">模拟数据每3秒刷新</span>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="downloadPNG('orders')">PNG</el-button>
                <el-button size="small" type="text" @click="downloadCSV('orders')">CSV</el-button>
                <el-button size="small" type="text" @click="downloadExcel('orders')">Excel</el-button>
              </div>
            </div>
          </template>
          <div class="chart-area">
            <div ref="ordersChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第二行：玫瑰饼图 + KPI 横排卡 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24" :lg="14">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div class="card-header__left">
                <span class="card-header__title">产品类别占比（玫瑰图）</span>
                <span class="card-header__hint">点击类别查看子类别</span>
                <el-breadcrumb v-if="inDrilldown" class="card-header__breadcrumb" separator="/">
                  <el-breadcrumb-item>类别占比</el-breadcrumb-item>
                  <el-breadcrumb-item>{{ currentCategory }}</el-breadcrumb-item>
                </el-breadcrumb>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="resetPie()">返回主数据</el-button>
                <el-button size="small" type="text" @click="downloadPNG('category')">PNG</el-button>
                <el-button size="small" type="text" @click="downloadCSV('category')">CSV</el-button>
                <el-button size="small" type="text" @click="downloadExcel('category')">Excel</el-button>
              </div>
            </div>
          </template>
          <div class="chart-area">
            <div ref="categoryChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>

      <el-col :xs="24" :lg="10">
        <el-row :gutter="12">
          <el-col :xs="24" :sm="8">
            <el-card shadow="hover" class="kpi-card">
              <div class="kpi-card__header">转化率</div>
              <div class="kpi-card__value">{{ kpi.conversion }}%</div>
              <div class="kpi-card__desc">近{{ filters.period }}日平均（模拟）</div>
            </el-card>
          </el-col>
          <el-col :xs="24" :sm="8">
            <el-card shadow="hover" class="kpi-card">
              <div class="kpi-card__header">留存率</div>
              <div class="kpi-card__value">{{ kpi.retention }}%</div>
              <div class="kpi-card__desc">客户留存（模拟）</div>
            </el-card>
          </el-col>
          <el-col :xs="24" :sm="8">
            <el-card shadow="hover" class="kpi-card">
              <div class="kpi-card__header">客单价</div>
              <div class="kpi-card__value">¥{{ kpi.aov }}</div>
              <div class="kpi-card__desc">平均订单金额（模拟）</div>
            </el-card>
          </el-col>
        </el-row>
      </el-col>
    </el-row>

    <!-- 第三行：雷达 + 仪表盘 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div>
                <span class="card-header__title">渠道表现雷达图</span>
                <span class="card-header__hint">模拟数据每3秒刷新</span>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="downloadPNG('radar')">PNG</el-button>
              </div>
            </div>
          </template>
          <div class="chart-area">
            <div ref="radarChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>
      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div>
                <span class="card-header__title">系统健康度仪表盘</span>
                <span class="card-header__hint">模拟数据每3秒波动</span>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="downloadPNG('gauge')">PNG</el-button>
              </div>
            </div>
          </template>
          <div class="chart-area">
            <div ref="gaugeChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第四行：散点 + 日历热力图 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <span class="card-header__title">客户分布散点图</span>
              <span class="card-header__hint">模拟数据</span>
            </div>
          </template>
          <div class="chart-area">
            <div ref="scatterChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>
      <el-col :xs="24" :lg="12">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <span class="card-header__title">日历热力图</span>
              <span class="card-header__hint">模拟数据</span>
            </div>
          </template>
          <div class="chart-area">
            <div ref="heatmapChartRef" class="chart-area__canvas"></div>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 第五行：地图可视化 -->
    <el-row :gutter="16" class="dashboard__row">
      <el-col :xs="24">
        <el-card shadow="never">
          <template #header>
            <div class="card-header">
              <div class="card-header__left">
                <span class="card-header__title">地图可视化</span>
                <span class="card-header__hint">选择区域并加载本地 geoJSON</span>
                <el-select v-model="mapRegion" size="small" class="map__selector">
                  <el-option label="中国" value="china" />
                  <el-option label="世界" value="world" />
                  <el-option label="广东省示例" value="gd" />
                </el-select>
              </div>
              <div class="card-header__actions">
                <el-button size="small" type="text" @click="downloadPNG('map')">PNG</el-button>
              </div>
            </div>
          </template>

          <div v-if="mapError" class="map__alert">
            <el-alert
              :title="mapError"
              type="warning"
              :closable="false"
              description="请将 geoJSON 文件放置于 /public/maps 目录，例如：world.json、china.json、provinces/guangdong.json"
            />
          </div>

          <div class="chart-area">
            <div ref="mapChartRef" class="chart-area__canvas map__canvas"></div>
          </div>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts";

defineOptions({ name: "DashboardView" });

// 统计数据（基础模拟）
const stats = ref({
  totalUsers: 1234,
  todayOrders: 56,
  totalProducts: 789,
  monthlyRevenue: 125680,
});

// KPI 模拟
const kpi = ref({ conversion: 78, retention: 82, aov: 268 });

// 筛选控件
const filters = ref<{ dateRange: [Date, Date] | null; period: "7" | "30" }>({
  dateRange: null,
  period: "7",
});
function applyFilters() {
  refreshAllCharts();
}

// 模拟数据生成
function rand(min: number, max: number) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
function genSeries(count: number, min = 50, max = 200) {
  return Array.from({ length: count }, () => rand(min, max));
}
function genPie() {
  return [
    { value: rand(400, 1200), name: "电子产品" },
    { value: rand(300, 900), name: "家居" },
    { value: rand(200, 800), name: "服饰" },
    { value: rand(200, 700), name: "食品" },
    { value: rand(100, 500), name: "其他" },
  ];
}
const subCategoryMap: Record<string, { value: number; name: string }[]> = {
  电子产品: [
    { value: rand(100, 400), name: "手机" },
    { value: rand(80, 300), name: "电脑" },
    { value: rand(60, 200), name: "配件" },
  ],
  家居: [
    { value: rand(80, 300), name: "家具" },
    { value: rand(60, 200), name: "装饰" },
    { value: rand(50, 180), name: "收纳" },
  ],
  服饰: [
    { value: rand(80, 280), name: "男装" },
    { value: rand(80, 280), name: "女装" },
    { value: rand(60, 200), name: "童装" },
  ],
  食品: [
    { value: rand(60, 240), name: "零食" },
    { value: rand(60, 240), name: "饮料" },
    { value: rand(60, 240), name: "生鲜" },
  ],
  其他: [
    { value: rand(40, 160), name: "文具" },
    { value: rand(40, 160), name: "礼品" },
  ],
};
function genRadar() {
  return [rand(50, 90), rand(40, 85), rand(45, 95), rand(30, 80), rand(35, 88)];
}
function genScatter(n = 120) {
  return Array.from({ length: n }, () => [rand(0, 100), rand(0, 100), rand(0, 2)]);
}
function genCalendarHeatData(year: number, month: number) {
  const days = new Date(year, month, 0).getDate();
  return Array.from({ length: days }, (_, i) => {
    const day = i + 1;
    const d = `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
    return [d, rand(0, 200)];
  });
}

// refs
const salesChartRef = ref<HTMLElement | null>(null);
const ordersChartRef = ref<HTMLElement | null>(null);
const categoryChartRef = ref<HTMLElement | null>(null);
const radarChartRef = ref<HTMLElement | null>(null);
const gaugeChartRef = ref<HTMLElement | null>(null);
const scatterChartRef = ref<HTMLElement | null>(null);
const heatmapChartRef = ref<HTMLElement | null>(null);
const mapChartRef = ref<HTMLElement | null>(null);

// instances
let salesChart: echarts.ECharts | null = null;
let ordersChart: echarts.ECharts | null = null;
let categoryChart: echarts.ECharts | null = null;
let radarChart: echarts.ECharts | null = null;
let gaugeChart: echarts.ECharts | null = null;
let scatterChart: echarts.ECharts | null = null;
let heatmapChart: echarts.ECharts | null = null;
let mapChart: echarts.ECharts | null = null;

// 状态：饼图钻取
let inDrilldown = false;
let currentCategory = "";

// 地图选择与错误提示
const mapRegion = ref<"china" | "world" | "gd">("china");
const mapError = ref<string | null>(null);

// 初始化图表
function initSalesChart() {
  if (!salesChartRef.value) return;
  salesChart = echarts.init(salesChartRef.value);
  salesChart.setOption({
    legend: { top: 8, textStyle: { color: "#606266" } },
    grid: { left: 24, right: 24, top: 40, bottom: 24 },
    tooltip: { trigger: "axis" },
    xAxis: {
      type: "category",
      boundaryGap: false,
      axisLine: { lineStyle: { color: "#dcdfe6" } },
      axisLabel: { color: "#606266" },
      data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    },
    yAxis: { type: "value", splitLine: { lineStyle: { color: "#ebeef5" } }, axisLabel: { color: "#606266" } },
    series: [
      {
        name: "销售额（本周）",
        type: "line",
        smooth: true,
        symbol: "circle",
        symbolSize: 6,
        lineStyle: { width: 2, color: "#4e73df" },
        itemStyle: { color: "#4e73df" },
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: "rgba(78,115,223,0.35)" },
            { offset: 1, color: "rgba(78,115,223,0.05)" },
          ]),
        },
        data: genSeries(7),
      },
      {
        name: "销售额（上周）",
        type: "line",
        smooth: true,
        symbol: "circle",
        symbolSize: 6,
        lineStyle: { width: 2, color: "#909399", type: "dashed" },
        itemStyle: { color: "#909399" },
        data: genSeries(7, 40, 180),
      },
    ],
  });
}
function initOrdersChart() {
  if (!ordersChartRef.value) return;
  ordersChart = echarts.init(ordersChartRef.value);
  ordersChart.setOption({
    legend: { top: 8, textStyle: { color: "#606266" } },
    grid: { left: 24, right: 24, top: 40, bottom: 24 },
    tooltip: { trigger: "axis" },
    xAxis: {
      type: "category",
      axisLine: { lineStyle: { color: "#dcdfe6" } },
      axisLabel: { color: "#606266" },
      data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    },
    yAxis: { type: "value", splitLine: { lineStyle: { color: "#ebeef5" } }, axisLabel: { color: "#606266" } },
    series: [
      {
        name: "订单量（本周）",
        type: "bar",
        data: genSeries(7, 30, 140),
        itemStyle: { color: "#1cc88a" },
        barMaxWidth: 36,
        markLine: {
          data: [{ type: "average", name: "平均" }],
          lineStyle: { color: "#909399" },
          label: { color: "#606266" },
        },
      },
      {
        name: "订单量（上周）",
        type: "bar",
        data: genSeries(7, 20, 120),
        itemStyle: { color: "#36b9cc" },
        barMaxWidth: 36,
      },
    ],
  });
}
function initCategoryChart() {
  if (!categoryChartRef.value) return;
  categoryChart = echarts.init(categoryChartRef.value);
  categoryChart.setOption({
    tooltip: { trigger: "item" },
    legend: { top: "top", textStyle: { color: "#606266" } },
    series: [
      {
        name: "类别占比",
        type: "pie",
        roseType: "radius",
        radius: ["30%", "65%"],
        center: ["50%", "55%"],
        avoidLabelOverlap: true,
        itemStyle: { borderRadius: 8, borderColor: "#fff", borderWidth: 2 },
        label: { show: true, color: "#606266" },
        labelLine: { show: true, lineStyle: { color: "#dcdfe6" } },
        data: genPie(),
      },
    ],
  });
  categoryChart.on("click", (params: any) => {
    const name: string = params?.data?.name;
    if (!name || !subCategoryMap[name]) return;
    currentCategory = name;
    inDrilldown = true;
    categoryChart?.setOption({ series: [{ name: `${name} - 子类别`, data: subCategoryMap[name] }] });
  });
}
function resetPie() {
  inDrilldown = false;
  currentCategory = "";
  categoryChart?.setOption({ series: [{ name: "类别占比", data: genPie(), roseType: "radius" }] });
}
function initRadarChart() {
  if (!radarChartRef.value) return;
  radarChart = echarts.init(radarChartRef.value);
  radarChart.setOption({
    tooltip: {},
    radar: {
      indicator: [
        { name: "官网", max: 100 },
        { name: "APP", max: 100 },
        { name: "线下门店", max: 100 },
        { name: "第三方平台", max: 100 },
        { name: "社交媒体", max: 100 },
      ],
      splitLine: { lineStyle: { color: "#ebeef5" } },
      axisLine: { lineStyle: { color: "#dcdfe6" } },
      splitArea: { areaStyle: { color: ["#f8f9fc"] } },
    },
    series: [
      {
        type: "radar",
        areaStyle: { color: "rgba(28,200,138,0.25)" },
        lineStyle: { color: "#1cc88a" },
        itemStyle: { color: "#1cc88a" },
        data: [{ value: genRadar(), name: "渠道表现" }],
      },
    ],
  });
}
function initGaugeChart() {
  if (!gaugeChartRef.value) return;
  gaugeChart = echarts.init(gaugeChartRef.value);
  gaugeChart.setOption({
    tooltip: { formatter: "{a} <br/>{b} : {c}%" },
    series: [
      {
        name: "健康度",
        type: "gauge",
        progress: { show: true, width: 12 },
        axisLine: { lineStyle: { width: 12 } },
        detail: { valueAnimation: true, formatter: "{value}%", color: "#303133" },
        data: [{ value: rand(60, 95), name: "系统健康度" }],
      },
    ],
  });
}
function initScatterChart() {
  if (!scatterChartRef.value) return;
  scatterChart = echarts.init(scatterChartRef.value);
  const data = genScatter(150);
  scatterChart.setOption({
    tooltip: { trigger: "item" },
    legend: { top: 8, data: ["A 类", "B 类", "C 类"], textStyle: { color: "#606266" } },
    grid: { left: 24, right: 24, top: 40, bottom: 24 },
    xAxis: {
      type: "value",
      min: 0,
      max: 100,
      axisLine: { lineStyle: { color: "#dcdfe6" } },
      splitLine: { lineStyle: { color: "#ebeef5" } },
    },
    yAxis: {
      type: "value",
      min: 0,
      max: 100,
      axisLine: { lineStyle: { color: "#dcdfe6" } },
      splitLine: { lineStyle: { color: "#ebeef5" } },
    },
    series: [
      {
        name: "A 类",
        type: "scatter",
        data: data.filter((d) => d[2] === 0).map((d) => [d[0], d[1]]),
        itemStyle: { color: "#4e73df" },
      },
      {
        name: "B 类",
        type: "scatter",
        data: data.filter((d) => d[2] === 1).map((d) => [d[0], d[1]]),
        itemStyle: { color: "#1cc88a" },
      },
      {
        name: "C 类",
        type: "scatter",
        data: data.filter((d) => d[2] === 2).map((d) => [d[0], d[1]]),
        itemStyle: { color: "#36b9cc" },
      },
    ],
  });
}
function initHeatmapChart() {
  if (!heatmapChartRef.value) return;
  heatmapChart = echarts.init(heatmapChartRef.value);
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;
  heatmapChart.setOption({
    tooltip: { position: "top" },
    visualMap: { min: 0, max: 200, calculable: true, orient: "horizontal", left: "center", top: 16 },
    calendar: { top: 64, left: 24, right: 24, cellSize: [20, 20], range: `${year}-${String(month).padStart(2, "0")}` },
    series: [{ type: "heatmap", coordinateSystem: "calendar", data: genCalendarHeatData(year, month) }],
  });
}

// 地图：加载与渲染
async function loadGeoJSON(region: "china" | "world" | "gd"): Promise<any | null> {
  try {
    const path =
      region === "china"
        ? "/maps/china.json"
        : region === "world"
        ? "/maps/world.json"
        : "/maps/provinces/guangdong.json";
    const res = await fetch(path);
    if (!res.ok) throw new Error(`无法加载 ${path}`);
    const json = await res.json();
    return json;
  } catch (err: any) {
    return null;
  }
}
async function initMapChart() {
  if (!mapChartRef.value) return;
  mapChart = echarts.init(mapChartRef.value);
  await renderMap();
}
async function renderMap() {
  mapError.value = null;
  const json = await loadGeoJSON(mapRegion.value);
  if (!json) {
    mapError.value = "未找到对应 geoJSON 文件或加载失败";
    mapChart?.clear();
    return;
  }
  const mapName =
    mapRegion.value === "china" ? "中国" : mapRegion.value === "world" ? "世界" : "广东";
  echarts.registerMap(mapName, json);
  const data = (json.features || []).map((f: any) => ({
    name: f.properties?.name || "",
    value: rand(10, 500),
  }));
  mapChart?.setOption({
    tooltip: { trigger: "item" },
    visualMap: {
      min: 0,
      max: 500,
      left: 20,
      bottom: 20,
      text: ["高", "低"],
      calculable: true,
    },
    series: [
      {
        name: "地区指标",
        type: "map",
        map: mapName,
        roam: true,
        label: { show: false },
        itemStyle: { borderColor: "#dcdfe6" },
        emphasis: { label: { show: true } },
        data,
      },
    ],
  });
}

// 刷新逻辑（模拟周期）
let refreshTimer: number | null = null;
function refreshAllCharts() {
  // 折线：本周/上周
  salesChart?.setOption({ series: [{ data: genSeries(7) }, { data: genSeries(7, 40, 180) }] });
  // 柱状：本周/上周
  ordersChart?.setOption({ series: [{ data: genSeries(7, 30, 140) }, { data: genSeries(7, 20, 120) }] });
  // 饼：钻取或主数据
  if (inDrilldown && currentCategory && subCategoryMap[currentCategory]) {
    categoryChart?.setOption({ series: [{ data: subCategoryMap[currentCategory] }] });
  } else {
    categoryChart?.setOption({ series: [{ data: genPie() }] });
  }
  // 雷达
  radarChart?.setOption({ series: [{ data: [{ value: genRadar(), name: "渠道表现" }] }] });
  // 仪表盘 & KPI
  const health = rand(60, 95);
  gaugeChart?.setOption({ series: [{ data: [{ value: health, name: "系统健康度" }] }] });
  const convMin = filters.value.period === "7" ? 70 : 60;
  const convMax = filters.value.period === "7" ? 90 : 85;
  kpi.value.conversion = rand(convMin, convMax);
  kpi.value.retention = rand(75, 90);
  kpi.value.aov = rand(180, 360);
  // 散点
  const data = genScatter(150);
  scatterChart?.setOption({
    series: [
      { data: data.filter((d) => d[2] === 0).map((d) => [d[0], d[1]]) },
      { data: data.filter((d) => d[2] === 1).map((d) => [d[0], d[1]]) },
      { data: data.filter((d) => d[2] === 2).map((d) => [d[0], d[1]]) },
    ],
  });
  // 日历热力图
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;
  heatmapChart?.setOption({ series: [{ data: genCalendarHeatData(year, month) }] });
  // 地图数据刷新（保持当前区域）
  renderMap();
}

// 导出 PNG/CSV/Excel（无 PDF）
function triggerDownload(dataUrl: string, filename: string) {
  const a = document.createElement("a");
  a.href = dataUrl;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}
function toCSV(rows: string[][]) {
  return rows.map((r) => r.map((c) => `"${String(c).replace(/"/g, '""')}"`).join(",")).join("\n");
}
function downloadPNG(which: "sales" | "orders" | "category" | "radar" | "gauge" | "scatter" | "heatmap" | "map") {
  const mapInst: Record<string, echarts.ECharts | null> = {
    sales: salesChart,
    orders: ordersChart,
    category: categoryChart,
    radar: radarChart,
    gauge: gaugeChart,
    scatter: scatterChart,
    heatmap: heatmapChart,
    map: mapChart,
  };
  const inst = mapInst[which];
  if (!inst) return;
  const url = inst.getDataURL({ type: "png", pixelRatio: 2, backgroundColor: "#fff" });
  triggerDownload(url, `${which}.png`);
}
function downloadCSV(which: "sales" | "orders" | "category") {
  let rows: string[][] = [];
  if (which === "sales" && salesChart) {
    const opt: any = salesChart.getOption();
    const x = (opt.xAxis?.[0]?.data as string[]) || [];
    const s1 = (opt.series?.[0]?.data as number[]) || [];
    const s2 = (opt.series?.[1]?.data as number[]) || [];
    rows = [["Day", "本周销售额", "上周销售额"], ...x.map((d, i) => [d, String(s1[i] ?? ""), String(s2[i] ?? "")])];
  } else if (which === "orders" && ordersChart) {
    const opt: any = ordersChart.getOption();
    const x = (opt.xAxis?.[0]?.data as string[]) || [];
    const s1 = (opt.series?.[0]?.data as number[]) || [];
    const s2 = (opt.series?.[1]?.data as number[]) || [];
    rows = [["Day", "本周订单量", "上周订单量"], ...x.map((d, i) => [d, String(s1[i] ?? ""), String(s2[i] ?? "")])];
  } else if (which === "category" && categoryChart) {
    const opt: any = categoryChart.getOption();
    const data = (opt.series?.[0]?.data as { name: string; value: number }[]) || [];
    rows = [["Category", "Value"], ...data.map((it) => [it.name, String(it.value)])];
  }
  const csv = toCSV(rows);
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
  const url = URL.createObjectURL(blob);
  triggerDownload(url, `${which}.csv`);
  URL.revokeObjectURL(url);
}
function downloadExcel(which: "sales" | "orders" | "category") {
  let rows: string[][] = [];
  if (which === "sales" && salesChart) {
    const opt: any = salesChart.getOption();
    const x = (opt.xAxis?.[0]?.data as string[]) || [];
    const s1 = (opt.series?.[0]?.data as number[]) || [];
    const s2 = (opt.series?.[1]?.data as number[]) || [];
    rows = [["Day", "本周销售额", "上周销售额"], ...x.map((d, i) => [d, String(s1[i] ?? ""), String(s2[i] ?? "")])];
  } else if (which === "orders" && ordersChart) {
    const opt: any = ordersChart.getOption();
    const x = (opt.xAxis?.[0]?.data as string[]) || [];
    const s1 = (opt.series?.[0]?.data as number[]) || [];
    const s2 = (opt.series?.[1]?.data as number[]) || [];
    rows = [["Day", "本周订单量", "上周订单量"], ...x.map((d, i) => [d, String(s1[i] ?? ""), String(s2[i] ?? "")])];
  } else if (which === "category" && categoryChart) {
    const opt: any = categoryChart.getOption();
    const data = (opt.series?.[0]?.data as { name: string; value: number }[]) || [];
    rows = [["Category", "Value"], ...data.map((it) => [it.name, String(it.value)])];
  }
  const tableRows = rows.map((r) => `<tr>${r.map((c) => `<td>${String(c)}</td>`).join("")}</tr>`).join("");
  const html = `<!DOCTYPE html><html><head><meta charset="utf-8" /><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8" /></head><body><table>${tableRows}</table></body></html>`;
  const blob = new Blob([html], { type: "application/vnd.ms-excel" });
  const url = URL.createObjectURL(blob);
  triggerDownload(url, `${which}.xls`);
  URL.revokeObjectURL(url);
}

// 尺寸自适应
function handleResize() {
  salesChart?.resize();
  ordersChart?.resize();
  categoryChart?.resize();
  radarChart?.resize();
  gaugeChart?.resize();
  scatterChart?.resize();
  heatmapChart?.resize();
  mapChart?.resize();
}

watch(mapRegion, async () => {
  await renderMap();
});

onMounted(async () => {
  initSalesChart();
  initOrdersChart();
  initCategoryChart();
  initRadarChart();
  initGaugeChart();
  initScatterChart();
  initHeatmapChart();
  await initMapChart();

  window.addEventListener("resize", handleResize);
  refreshAllCharts();

  refreshTimer = window.setInterval(() => {
    refreshAllCharts();
  }, 3000);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", handleResize);
  if (refreshTimer) {
    clearInterval(refreshTimer);
    refreshTimer = null;
  }
  salesChart?.dispose();
  ordersChart?.dispose();
  categoryChart?.dispose();
  radarChart?.dispose();
  gaugeChart?.dispose();
  scatterChart?.dispose();
  heatmapChart?.dispose();
  mapChart?.dispose();
  salesChart = null;
  ordersChart = null;
  categoryChart = null;
  radarChart = null;
  gaugeChart = null;
  scatterChart = null;
  heatmapChart = null;
  mapChart = null;
});
</script>

<style scoped lang="scss">
.dashboard {
  padding: 16px 20px;
  background-color: #f5f7fa;
  min-height: 100vh;

  &__header {
    margin-bottom: 16px;
  }
  &__title {
    font-size: 22px;
    font-weight: 600;
    color: #303133;
    margin-bottom: 4px;
  }
  &__subtitle {
    font-size: 14px;
    color: #909399;
  }
  &__row {
    margin-bottom: 16px;
  }
}

.dashboard__controls {
  margin-bottom: 16px;
  .controls__row {
    display: flex;
    gap: 12px;
    align-items: center;
    flex-wrap: wrap;
  }
}

.stat-card {
  &__header {
    font-size: 13px;
    color: #606266;
    margin-bottom: 8px;
  }
  &--primary {
    border-left: 4px solid #4e73df;
  }
  &--success {
    border-left: 4px solid #1cc88a;
  }
  &--info {
    border-left: 4px solid #36b9cc;
  }
  &--warning {
    border-left: 4px solid #f6c23e;
  }
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;

  &__title {
    font-size: 14px;
    font-weight: 600;
    color: #303133;
  }
  &__hint {
    font-size: 12px;
    color: #909399;
    margin-left: 8px;
  }
  &__actions {
    display: flex;
    gap: 8px;
  }
  &__left {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  &__breadcrumb {
    margin-left: 8px;
  }
}

.chart-area {
  &__canvas {
    width: 100%;
    height: 320px;
  }
}

.kpi-card {
  &__header {
    font-size: 13px;
    color: #606266;
    margin-bottom: 6px;
  }
  &__value {
    font-size: 18px;
    font-weight: 600;
    color: #303133;
    line-height: 1.3;
  }
  &__desc {
    font-size: 12px;
    color: #909399;
  }
}

.map {
  &__selector {
    margin-left: 12px;
    width: 160px;
  }
  &__alert {
    margin-bottom: 12px;
  }
  &__canvas {
    height: 420px;
  }
}
</style>